package com.example.srb.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.srb.common.exception.Assert;
import com.example.srb.common.result.ResponseEnum;
import com.example.srb.core.enums.LendStatusEnum;
import com.example.srb.core.enums.TransTypeEnum;
import com.example.srb.core.hfb.FormHelper;
import com.example.srb.core.hfb.HfbConst;
import com.example.srb.core.hfb.RequestHelper;
import com.example.srb.core.mapper.LendMapper;
import com.example.srb.core.mapper.UserAccountMapper;
import com.example.srb.core.pojo.bo.TransFlowBO;
import com.example.srb.core.pojo.entity.Lend;
import com.example.srb.core.pojo.entity.LendItem;
import com.example.srb.core.mapper.LendItemMapper;
import com.example.srb.core.pojo.vo.InvestVO;
import com.example.srb.core.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.srb.core.util.LendNoUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.querydsl.QuerydslRepositoryInvokerAdapter;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 标的出借记录表 服务实现类
 * </p>
 *
 * @author Helen
 * @since 2021-02-20
 */
@Service
@Slf4j
public class LendItemServiceImpl extends ServiceImpl<LendItemMapper, LendItem> implements LendItemService {

    @Resource
    private LendMapper lendMapper;
    @Resource
    private UserAccountService userAccountService;
    @Resource
    private LendService lendService;
    @Resource
    private UserBindService userBindService;
    @Resource
    private TransFlowService transFlowService;
    @Resource
    private UserAccountMapper userAccountMapper;

    @Override
    public String commitInvest(InvestVO investVO) {
        //输入校验==========================================
        Long lendId = investVO.getLendId();
        //获取标的信息
        Lend lend = lendMapper.selectById(lendId);

        //标的状态必须为募资中
        Assert.isTrue(lend.getStatus().intValue() == LendStatusEnum.INVEST_RUN.getStatus().intValue(),
                ResponseEnum.LEND_INVEST_ERROR);//当前状态无法投标

        //标的不能超卖：(已投金额 + 本次投资金额 ) >= 标的金额（超卖）
        BigDecimal sum = lend.getInvestAmount().add(new BigDecimal(investVO.getInvestAmount()));
        Assert.isTrue(sum.doubleValue() <= lend.getAmount().doubleValue(),
                ResponseEnum.LEND_FULL_SCALE_ERROR);

        //账户可用余额充足：当前用户的余额 >= 当前用户的投资金额（可以投资）
        Long investUserId = investVO.getInvestUserId();
        BigDecimal amount = userAccountService.getAccount(investUserId);
        Assert.isTrue(amount.doubleValue() >= Double.parseDouble(investVO.getInvestAmount()),
                ResponseEnum.NOT_SUFFICIENT_FUNDS_ERROR);//余额不足

        //在商户平台中生成投资信息==========================================
        //标的下的投资信息
        LendItem lendItem = new LendItem();
        lendItem.setInvestUserId(investUserId);//投资人id
        lendItem.setInvestName(investVO.getInvestName());//投资人名字
        String lendItemNo = LendNoUtils.getLendItemNo();
        lendItem.setLendItemNo(lendItemNo);//投资条目编号（一个Lend对应一个或多个LendItem）
        lendItem.setLendId(lendId);//对应的标的id
        lendItem.setInvestAmount(new BigDecimal(investVO.getInvestAmount()));//此笔投资金额
        lendItem.setLendYearRate(lend.getLendYearRate());//年化利率
        lendItem.setInvestTime(LocalDateTime.now());//投资时间
        lendItem.setLendStartDate(lend.getLendStartDate());//开始时间
        lendItem.setLendEndDate(lend.getLendEndDate());//结束时间
        //预期收益
        BigDecimal expectAmount = lendService.getInterestCount(
                lendItem.getInvestAmount(),
                lendItem.getLendYearRate(),
                lend.getPeriod(),
                lend.getReturnMethod());
        lendItem.setExpectAmount(expectAmount);
        //实际收益
        lendItem.setRealAmount(new BigDecimal(0));
        //默认状态，刚刚创建
        lendItem.setStatus(0);//状态（0：默认 1：已支付 2：已还款）
        baseMapper.insert(lendItem);

        //组装投资相关的参数，提交到汇付宝资金托管平台==========================================
        //在托管平台同步用户的投资信息，修改用户的账户资金信息==========================================
        String bindCode = userBindService.getBindCodeByUserId(investUserId);//获取投资人的绑定协议号
        String benefitBindCode = userBindService.getBindCodeByUserId(lend.getUserId());//获取借款人的绑定协议号


        //封装提交至汇付宝的参数
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("agentId", HfbConst.AGENT_ID);//商户唯一标识
        paramMap.put("voteBindCode",bindCode);//投资人绑定协议号
        paramMap.put("benefitBindCode",benefitBindCode);//借款人绑定协议号
        paramMap.put("agentProjectCode",lend.getLendNo());//项目编号
        paramMap.put("agentProjectName",lend.getTitle());//项目名称
        paramMap.put("agentBillNo",lendItemNo);//订单号，，在资金托管平台上的投资订单的唯一编号，要和lendItemNo保持一致。
        paramMap.put("voteAmt",investVO.getInvestAmount());//投资金额
        paramMap.put("votePrizeAmt","0");//投资奖励金额
        paramMap.put("voteFeeAmt","0");//商户手续费
        paramMap.put("projectAmt",lend.getAmount());//项目总金额
        paramMap.put("note","投资一笔交易");//投资备注
        paramMap.put("notifyUrl",HfbConst.INVEST_NOTIFY_URL);
        paramMap.put("returnUrl",HfbConst.INVEST_RETURN_URL);
        paramMap.put("timestamp", RequestHelper.getTimestamp());//时间戳
        paramMap.put("sign",RequestHelper.getSign(paramMap));//验签参数


        //构建充值自动提交表单
        String formStr = FormHelper.buildForm(HfbConst.INVEST_URL, paramMap);
        return formStr;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void notify(Map<String, Object> paramMap) {
        log.info("用户投资成功！");

        //获取投资编号
        String agentBillNo = (String) paramMap.get("agentBillNo");

        //幂等性判断
        Boolean result = transFlowService.isSaveTransFlow(agentBillNo);
        if (result){
            log.warn("幂等性返回");
            return;
        }

        //获取用户的绑定协议号
        String voteBindCode = (String) paramMap.get("voteBindCode");
        //获取用户的投资金额
        String voteAmt = (String) paramMap.get("voteAmt");
        //修改商户系统中的用户账户金额：余额、冻结金额
//        userAccountMapper.updateAccount(voteBindCode,new BigDecimal("-"  + voteAmt),new BigDecimal(voteAmt));
        userAccountMapper.updateAccount(voteBindCode,new BigDecimal(voteAmt).negate(),new BigDecimal(voteAmt));

        //修改投资记录的投资状态改为已支付
        LendItem lendItem = this.getByLendItemNo(agentBillNo);
        lendItem.setStatus(1);//状态（0：默认 1：已支付 2：已还款）
        baseMapper.updateById(lendItem);

        //修改标的信息：投资人数、已投金额
        Long lendId = lendItem.getLendId();
        Lend lend = lendMapper.selectById(lendId);
        lend.setInvestNum(lend.getInvestNum() + 1 );
        lend.setInvestAmount(lend.getInvestAmount().add(lendItem.getInvestAmount()));
        lendMapper.updateById(lend);

        //新增交易流水
        TransFlowBO transFlowBO = new TransFlowBO();
        transFlowBO.setAgentBillNo(agentBillNo);
        transFlowBO.setBindCode(voteBindCode);
        transFlowBO.setAmount(new BigDecimal(voteAmt));
        transFlowBO.setTransTypeEnum(TransTypeEnum.INVEST_LOCK);//投标锁定
        transFlowBO.setMemo("投资项目编号：" + lend.getLendNo() + "项目名称：" + lend.getTitle());
        transFlowService.saveTransFlow(transFlowBO);
    }

    @Override
    public List<LendItem> selectByLendId(Long lendId, Integer status) {
        QueryWrapper<LendItem> wrapper = new QueryWrapper<>();
        wrapper.eq("lend_id",lendId)
                .eq("status",status);
        return baseMapper.selectList(wrapper);
    }

    @Override
    public List<LendItem> selectByLendId(Long lendId) {
        QueryWrapper<LendItem> wrapper = new QueryWrapper<>();
        wrapper.eq("lend_id",lendId);
        return baseMapper.selectList(wrapper);
    }

    public LendItem getByLendItemNo(String lendItemNo){
        QueryWrapper<LendItem> wrapper = new QueryWrapper<>();
        wrapper.eq("lend_item_no",lendItemNo);
        return baseMapper.selectOne(wrapper);
    }


}
